
#include <libcoco.h>
#include "aco.h"
// #include <assert.h>
#include <dbg.h>
#include <compl/candy.h>
#define CROUT_MALLOC(size)      __builtin_malloc(size)
#define CROUT_FREE(ptr, size)   __builtin_free(ptr)

typedef struct crout_int{
    // word_t   stk_size;
    void *(*routine)(void*);
    void *arg;
    void *ret;
    aco_t *aco;
    size_t stk_size;
}crout_int_t;

static TLS_INITIAL aco_t *thread_prev_aco;
static NORETURN void async_worker(){
    crout_int_t * cr = aco_get_arg();
    // aco_yield();
    cr->ret = cr->routine(cr->arg);
    // aco_gtls_co->main_co = thread_prev_aco;
    // dbg_printf("%p -> %p, real %p -> %p\n", cr->aco, cr->aco->main_co, aco_gtls_co, aco_gtls_co->main_co);
    /* 只能自己定义tls变量维护当前最新的aco, 维持一个链式结构 */
    aco_exit();/* aco_exit只会返回创建时的main co, 有问题*/

    // aco_yield1(thread_cur_aco);
}

/* 全局初始化 */
// static aco_t *glbaco;
static __attribute__((constructor)) void aco_sysinit(){
    aco_thread_init(NULL);
    aco_gtls_co = aco_create(NULL, NULL, 0, NULL, NULL);
    // glbaco = aco_gtls_co;
}

int 	crout_create( crout_t **pco,const crout_attr_t *attr,void *(*routine)(void*),void *arg){
    void *p = CROUT_MALLOC(sizeof(crout_int_t));
    if (!p) return -1;
    crout_int_t * cr = (crout_int_t *)p;
    
    cr->stk_size = (size_t)attr->stack_size;
    aco_t *cur_aco = aco_get_co();
    // assert(cur_aco == glbaco);
    // if (!cur_aco) cur_aco = aco_create(NULL, NULL, 0, NULL, NULL);
    aco_share_stack_t* sstk = aco_share_stack_new2(cr->stk_size, 0);

    cr->routine = routine;
    cr->arg = arg;
    cr->aco = aco_create(cur_aco, sstk, sstk->real_sz, async_worker, cr);
    *pco = (crout_t *)cr;
    
    // aco_resume(cr->aco);
    return 0;
}

void    crout_resume( crout_t *co){
    crout_int_t *cr = (crout_int_t *)co;
    // coroutine_resume(cr->S, cr->coid);
    /* 当前co */
    // thread_prev_aco = aco_gtls_co;
    
    /* 设置返回co为当前co似乎不行? */
    cr->aco->main_co = aco_get_co();
    // thread_cur_aco = cr->aco;
    aco_resume(cr->aco);
}


void    crout_yield( crout_t *co ){
    /* 此处co是当前co */
    crout_int_t *cr = (crout_int_t *)co;

    // ASSERT(cr->aco == aco_gtls_co);
    
    aco_yield();
}

void    crout_release( crout_t *co ){
    crout_int_t *cr = (crout_int_t *)co;
    // coroutine_close(cr->S);
    aco_destroy(cr->aco);
    CROUT_FREE(cr, sizeof(crout_int_t));
}

void    crout_reset(crout_t * co){
    crout_int_t *cr = (crout_int_t *)co;
    aco_destroy(cr->aco);
    aco_t *cur_aco = aco_get_co();
    // if (!cur_aco) cur_aco = aco_create(NULL, NULL, 0, NULL, NULL);
    aco_share_stack_t* sstk = aco_share_stack_new2(cr->stk_size, 0);
    cr->aco = aco_create(cur_aco, sstk, sstk->real_sz, async_worker, cr);
    // aco_resume(cr->aco);
}
